#include "uae.h"
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
uae::uae(int num_act, int** payoffs ,double learn_rate){

	uae::num_actions = num_act;
	learning_rate = learn_rate;
	uae::payoffs = payoffs;
	rewards = new vector<int>();
	strategies = new vector<double*>();
	his_actions = new vector<int>();
	my_actions = new vector<int>();
	
	
	max = INT_MIN;
	min = INT_MAX;
	int i, j;
	for (i = 0; i < num_actions; i++) {
		for (j = 0; j < num_actions; j++) {
			if (payoffs[i][j] > max){
				max = payoffs[i][j];
				max_act = i;
			}
			if (payoffs[i][j] < min)
				min = payoffs[i][j];

			//printf("%i ", payoffs[i][j]);
		}
		//printf("\n");
	}



	alpha =  max;

	double* stra = new double[num_actions];
	for (int i=0; i < num_actions; i++)
		if(i == max_act)
			stra[i] = 1;
		else 
			stra[i] = 0;
	strategies->push_back(stra);
	Time = 0;

}
uae::~uae(){
	delete rewards;
	delete strategies;
}

int uae::Move(){

	double * stra = strategies->at(Time);
	//printV(stra);

	double sum = 0;
	for(int i = 0; i < num_actions; i++){
		if(stra[i] >= 0.0001){
			double r = (rand()%100000)/100000.0;
			sum += stra[i];
			//printf("random is %.3f, sum is %.3f\n",r,sum);
			if(r<= sum){
				Time ++;
				return i;
			}
		}
	}


	return -1;

}
void uae::Update(int* actions, double r_t){
	rewards->push_back(r_t);
	my_actions->push_back(actions[0]);
	his_actions->push_back(actions[1]);
	//update alpha
	alpha = (1-learning_rate) * alpha + learning_rate * r_t;

	//printf("==========\nalpha is %.2f/ reward is %.2f\n",alpha, r_t);
	/* playing statisficing */
	double* stra = new double[num_actions];

	if(alpha > (double)r_t){
		//printf("----->playing random\n");
		//play random
		int act = rand() % num_actions;
		for (int i = 0; i < num_actions; i++){
			if (act == i)
				stra[i] = 1;
			else 
				stra[i] = 0;
		}
		//printV(stra);
	}
	else{
		/*
		// redo previous strategy
		double * prev = strategies->at(Time-1);
		for(int i =0 ; i < num_actions; i++)
			stra[i] = prev[i];
		*/
		//redo previous action
		for(int i =0 ; i < num_actions; i++)
			if (i ==my_actions->at(Time-1 ))
				stra[i] = 1;
			else
				stra[i]=0;

		//printf("------->previous action at T%i was (%.1f,%.1f)\n", Time-1, prev[0],prev[1]);
	}

	/* Finding Regret action */
	int regret_act = regret();
	//printf("regreted action is %i\n", regret_act);
	if(regret_act != -1){ // we have regret, therefore adjust or strategy toward this action
		//do a mixed strategy
		double lemda = (max - alpha) / (alpha-min);
		if(lemda >= 1)
			lemda = 1/lemda;
		
		lemda*=learning_rate;

		//printf("lemda: %2.2f\n",lemda);
				
		for(int i = 0; i< num_actions; i++){
			if(i == regret_act)
				stra[i] = (1 - lemda) * stra[i] + lemda;
			else
				stra[i] = (1 - lemda) * stra[i] ;
		}

	}
	
	strategies->push_back(stra);
	
}
int uae::regret(){

	double max_regret = INT_MIN;
	int max_regret_action = -1;
	for (int a = 0; a< num_actions; a++){
		double act_regret = 0;

		for(int t=0; t < Time; t++){

			double rewards[4];
			for (int i = 0; i< num_actions; i++)
				rewards[i] = (double)payoffs[i][his_actions->at(t)] ;

					
			act_regret += (double)payoffs[a][his_actions->at(t)] - dot(rewards, strategies->at(t) );
			if(act_regret > max_regret){
				max_regret = act_regret;
				max_regret_action = a;
			}
		}
	}

	double threshold = sqrt( (double)Time);

	//printf("max regret %2.2f\n",max_regret);
	if (max_regret>threshold)
		return max_regret_action;
	else
		return -1;
}
double uae::dot(double* v1, double* v2){
	double sum = 0;
	for(int i = 0; i < num_actions; i++){
		sum += v1[i] * v2[i];
	}
	return sum;
}

void uae::printV(double* str){
	printf("(%");
	int i;
	for(i = 0; i< num_actions; i++){
		printf("%.2f",str[i]);
		if(i < num_actions - 1)
			printf(",");
	}
	printf(")\n");
}
